home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 21 / CU Amiga Magazine's Super CD-ROM 21 (1998)(EMAP Images)(GB)[!][issue 1998-04].iso / CUCD / Games / ADoom / ADoom_src / amiga_video.c < prev    next >
C/C++ Source or Header  |  1998-02-06  |  47KB  |  1,463 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #include <exec/exec.h>
  6. #include <dos/dos.h>
  7. #include <graphics/gfx.h>
  8. #include <graphics/gfxbase.h>
  9. #include <graphics/gfxmacros.h>
  10. #include <intuition/intuition.h>
  11. #include <libraries/asl.h>
  12. #include <libraries/lowlevel.h>
  13. #include <cybergraphics/cybergraphics.h>
  14. #include <devices/gameport.h>
  15. #include <devices/timer.h>
  16.  
  17. #include <proto/exec.h>
  18. #include <proto/dos.h>
  19. #include <proto/graphics.h>
  20. #include <proto/layers.h>
  21. #include <proto/intuition.h>
  22. #include <proto/asl.h>
  23. #include <proto/timer.h>
  24. #include <proto/lowlevel.h>
  25. #include <proto/cybergraphics.h>
  26.  
  27. #include "doomtype.h"
  28. #include "doomdef.h"
  29. #include "doomstat.h"
  30. #include "i_system.h"
  31. #include "i_video.h"
  32. #include "v_video.h"
  33. #include "m_argv.h"
  34. #include "d_main.h"
  35.  
  36. #include "amiga_median.h"
  37. #include "c2p_020.h"
  38. #include "c2p_030.h"
  39. #include "c2p_040.h"
  40. #include "c2p8_040_amlaukka.h"
  41. #include "amiga_mmu.h"
  42.  
  43. /*experimental_c2p_stuff***********************************************/
  44. extern int scaledviewwidth;
  45. void REGARGS (*c2p)(REG(a0, const UBYTE *chunky),
  46.                     REG(a1, UBYTE *raster),
  47.                     REG(a2, const UBYTE *chunky_end)) = NULL;
  48.  
  49. /**********************************************************************/
  50. extern struct ExecBase *SysBase;
  51. struct Library *AslBase = NULL;
  52. struct Library *CyberGfxBase = NULL;
  53. struct Library *LowLevelBase = NULL;
  54.  
  55. extern int cpu_type;
  56.  
  57. static struct ScreenModeRequester *video_smr = NULL;
  58. static struct Screen *video_screen = NULL;
  59. static struct Window *video_window = NULL;
  60. static struct BitMap video_bitmap[3] = {
  61.   {0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
  62.   {0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
  63.   {0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}}
  64. };
  65. static PLANEPTR video_raster[3] = {NULL, NULL, NULL};    /* contiguous bitplanes */
  66. static UBYTE *video_compare_buffer[3] = {NULL, NULL, NULL};    /* in fastmem */
  67. static struct RastPort video_rastport[3];
  68. static struct ScreenBuffer *video_sb[2] = {NULL, NULL};
  69. static struct DBufInfo *video_db = NULL;
  70. static struct MsgPort *video_mp = NULL;
  71. static int video_which = 0;
  72. static BYTE video_sigbit1 = -1;
  73. static BYTE video_sigbit2 = -1;
  74. static volatile BYTE video_sigbit3 = -1;
  75. static struct Task *video_maintask;
  76. static struct Task *video_fliptask = NULL;
  77. static int video_depth = 0;
  78. static int video_oscan_height;
  79. static ULONG video_colourtable[1 + 3*256 + 1];
  80. static volatile WORD video_palette_changed = 0;
  81. static BOOL video_is_ehb_mode = FALSE;
  82. static BOOL video_is_native_mode = FALSE;
  83. static BOOL video_is_cyber_mode = FALSE;
  84. static BOOL video_is_using_blitter = FALSE;
  85. static BOOL video_blit_is_in_progress = FALSE;
  86. static BOOL video_use_mmu = FALSE;
  87. static BOOL video_is_directcgx = FALSE;
  88. static BOOL video_doing_fps = FALSE;
  89. static BOOL video_bitmap_is_locked = FALSE;
  90. static APTR video_bitmap_handle;
  91. static int video_f_cache_mode;
  92. static int video_c_cache_mode;
  93. static struct RastPort video_temprp;
  94. static struct BitMap video_tmp_bm = {
  95.   0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
  96. };
  97. static UBYTE video_xlate[256];   /* xlate colour from 8-bit to 6-bit EHB */
  98. static UWORD __chip emptypointer[] = {
  99.   0x0000, 0x0000,    /* reserved, must be NULL */
  100.   0x0000, 0x0000,     /* 1 row of image data */
  101.   0x0000, 0x0000    /* reserved, must be NULL */
  102. };
  103.  
  104. /* gameport stuff */
  105. static struct MsgPort *gameport_mp = NULL;
  106. static struct IOStdReq *gameport_io = NULL;
  107. static BOOL gameport_is_open = FALSE;
  108. static BOOL gameport_io_in_progress = FALSE;
  109. static struct InputEvent gameport_ie;
  110. static BYTE gameport_ct;        /* controller type */
  111. struct GamePortTrigger gameport_gpt = {
  112.   GPTF_UPKEYS | GPTF_DOWNKEYS,    /* gpt_Keys */
  113.   0,                /* gpt_Timeout */
  114.   1,                /* gpt_XDelta */
  115.   1                /* gpt_YDelta */
  116. };
  117.  
  118. /* SEGA variables */
  119. static ULONG prevSega;
  120. static BOOL sega3_selected = FALSE;
  121. static BOOL sega6_selected = FALSE;
  122.  
  123. /****************************************************************************/
  124. struct Library *TimerBase = NULL;
  125. static struct MsgPort *timermp = NULL;
  126. static struct timerequest *timerio = NULL;
  127. static ULONG timerclosed = TRUE;
  128. static ULONG eclocks_per_second; /* EClock frequency in Hz */
  129.  
  130. static struct EClockVal start_time;
  131. static unsigned int blit_time = 0;
  132. static unsigned int safe_time = 0;
  133. static unsigned int c2p_time = 0;
  134. static unsigned int wpa8_time = 0;
  135. static unsigned int lock_time = 0;
  136. static unsigned int total_frames = 0;
  137.  
  138. /****************************************************************************/
  139. static __inline void start_timer (void)
  140. {
  141.   ReadEClock (&start_time);
  142. }
  143.  
  144. /****************************************************************************/
  145. static __inline unsigned int end_timer (void)
  146. {
  147.   struct EClockVal end_time;
  148.  
  149.   ReadEClock (&end_time);
  150.   return end_time.ev_lo - start_time.ev_lo;
  151. }
  152.  
  153. /****************************************************************************/
  154.  
  155. static char *mode_name (ULONG mode)
  156. /* Return a mode name for given mode, compatible with ASL mode requester */
  157. /* Use name in DisplayInfo database if available */
  158. /* else manually construct the name */
  159. {
  160.   APTR handle;
  161.   char *p;
  162.   struct NameInfo nameinfo;
  163.   struct DimensionInfo dimsinfo;
  164.   static char modename[DISPLAYNAMELEN + 4 + 4 + 11 + 1];
  165.  
  166.   p = modename;
  167.   *p = '\0';
  168.   if ((handle = FindDisplayInfo (mode & ~SPRITES)) != NULL) {
  169.     if (GetDisplayInfoData (handle, (UBYTE *)&nameinfo,
  170.                             sizeof(nameinfo), DTAG_NAME,
  171.                             NULL) > sizeof(struct QueryHeader)) {
  172.       p += sprintf (p, "%s", nameinfo.Name);
  173.     } else if (GetDisplayInfoData (handle, (UBYTE *)&dimsinfo,
  174.                                    sizeof(dimsinfo), DTAG_DIMS,
  175.                                    NULL) >= 66 /* sizeof(dimsinfo)*/) {
  176.       switch (mode & MONITOR_ID_MASK) {
  177.         case DEFAULT_MONITOR_ID:
  178.           p += sprintf (p, "DEFAULT:");      /* PAL or NTSC??? */
  179.           break;
  180.         case NTSC_MONITOR_ID:
  181.           p += sprintf (p, "NTSC:");
  182.           break;
  183.         case PAL_MONITOR_ID:
  184.           p += sprintf (p, "PAL:");
  185.           break;
  186.         case VGA_MONITOR_ID:
  187.           p += sprintf (p, "MULTISCAN:");
  188.           break;
  189.         case A2024_MONITOR_ID:
  190.           p += sprintf (p, "A2024:");
  191.           break;
  192.         case PROTO_MONITOR_ID:
  193.           p += sprintf (p, "PROTO:");
  194.           break;
  195.         case EURO72_MONITOR_ID:
  196.           p += sprintf (p, "EURO72:");
  197.           break;
  198.         case EURO36_MONITOR_ID:
  199.           p += sprintf (p, "EURO36:");
  200.           break;
  201.         case SUPER72_MONITOR_ID:
  202.           p += sprintf (p, "SUPER72:");
  203.           break;
  204.         case DBLNTSC_MONITOR_ID:
  205.           p += sprintf (p, "DBLNTSC:");
  206.           break;
  207.         case DBLPAL_MONITOR_ID:
  208.           p += sprintf (p, "DBLPAL:");
  209.           break;
  210.         default:
  211.           p += sprintf (p, "(unknown):");
  212.           break;
  213.       }
  214.       p += sprintf (p, "%d x %d",
  215.                     dimsinfo.Nominal.MaxX - dimsinfo.Nominal.MinX + 1,
  216.                     dimsinfo.Nominal.MaxY - dimsinfo.Nominal.MinY + 1);
  217.       if ((mode & HAM_KEY) != 0)
  218.         p += sprintf (p, " HAM");
  219.       if ((mode & EXTRAHALFBRITE_KEY) != 0)
  220.         p += sprintf (p, " EHB");
  221.       if ((mode & LACE) != 0)
  222.         p += sprintf (p, " Interlaced");
  223.     } else {
  224.       p += sprintf (p, "%s", "(unnamed)");
  225.       if ((mode & HAM_KEY) != 0)
  226.         p += sprintf (p, " HAM");
  227.       if ((mode & EXTRAHALFBRITE_KEY) != 0)
  228.         p += sprintf (p, " EHB");
  229.       if ((mode & LACE) != 0)
  230.         p += sprintf (p, " Interlaced");
  231.     }
  232.   } else {
  233.     p += sprintf (p, "%s", "(unavailable)");
  234.   }
  235.   return (modename);
  236. }
  237.  
  238. /****************************************************************************/
  239.  
  240. static ULONG parse_mode (char *modename)
  241. /* Modename may be descriptive name ("PAL Lores"), or hex ("$00420001" or */
  242. /* "0x12345678") or decimal ("32768"). */
  243. {
  244.   ULONG mode, reason;
  245.  
  246.   mode = INVALID_ID;
  247.   if (modename != NULL) {
  248.     if (modename[0] == '0' && modename[1] == 'x') {
  249.       if (sscanf (&modename[2], "%lx", &mode) != 1)
  250.         mode = INVALID_ID;
  251.     } else if (modename[0] == '$') {
  252.       if (sscanf (&modename[1], "%lx", &mode) != 1)
  253.         mode = INVALID_ID;
  254.     } else if (modename[0] >= '0' && modename[0] <= '9') {
  255.       if (sscanf (modename, "%ld", &mode) != 1)
  256.         mode = INVALID_ID;
  257.     } else {
  258.       while ((mode = NextDisplayInfo (mode)) != INVALID_ID) {
  259.         if ((mode & LORESDPF_KEY) == 0) {
  260.           /* printf ("$%08x  \"%s\"\n", mode, mode_name (mode)); */
  261.           if (strcmp (mode_name (mode), modename) == 0)
  262.             break;
  263.         }
  264.       }
  265.     }
  266.   }
  267.   if (FindDisplayInfo (mode) == NULL)
  268.     I_Error ("ScreenMode not in database: \"%s\"", modename);
  269.   if ((reason = ModeNotAvailable (mode)) != 0)
  270.     I_Error ("Mode $%08x is not available: %ld", mode, reason);
  271.   return (mode);
  272. }
  273.  
  274. /**********************************************************************/
  275. static void video_do_fps (struct RastPort *rp)
  276. {
  277.   ULONG x;
  278.   static struct EClockVal start_time = {0, 0};
  279.   struct EClockVal end_time;
  280.   char msg[4];
  281.  
  282.   ReadEClock (&end_time);
  283.   x = end_time.ev_lo - start_time.ev_lo;
  284.   if (x != 0) {
  285.     x = (eclocks_per_second + (x >> 1)) / x;   /* round to nearest */
  286.     msg[0] = (x % 1000) / 100 + '0';
  287.     msg[1] = (x % 100) / 10 + '0';
  288.     msg[2] = (x % 10) + '0';
  289.     msg[3] = '\0';
  290.     Move (rp, SCREENWIDTH - 24, 6);
  291.     Text (rp, msg, 3);
  292.   }
  293.   start_time = end_time;
  294. }
  295.  
  296. /**********************************************************************/
  297. // This asynchronous task waits in a loop for sigbit3 signals.
  298. // Sigbit3 is signalled when the next frame is just finished.
  299. // Sigbit3 may be signalled from the qblit() cleanup function or from the
  300. // main task.
  301. // On receipt of sigbit3, we load the new palette and call ChangeScreenBuffer().
  302. // This way there is no delay calling ChangeScreenBuffer() after the last blit
  303. // has finished.
  304. // The main 3D rendering task may be interrupted to call ChangeScreenBuffer()
  305. // SIGBREAKF_CTRL_F and SIGBREAKF_CTRL_C are used for synchronisation
  306. // with the main task.
  307.  
  308. static void __saveds __interrupt video_flipscreentask (void)
  309. {
  310.   ULONG sig;
  311.   struct MsgPort *video_dispport, *video_safeport;
  312.   BOOL going, video_disp, video_safe;
  313.   int i;
  314.  
  315.   video_sigbit3 = AllocSignal(-1);
  316.   Signal (video_maintask, SIGBREAKF_CTRL_F);
  317.   video_dispport = CreatePort (NULL, 0);
  318.   video_safeport = CreatePort (NULL, 0);
  319.   video_disp = TRUE;
  320.   video_safe = TRUE;
  321.   for (i = 0; i < 2; i++) {
  322.     video_sb[i]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = video_dispport;
  323.     video_sb[i]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = video_safeport;
  324.   }
  325.   going = (video_sigbit3 != -1) &&
  326.           (video_dispport != NULL) &&
  327.           (video_safeport != NULL);
  328.   while (going) {
  329.     sig = Wait (1 << video_sigbit3 | SIGBREAKF_CTRL_C);
  330.     if ((sig & (1 << video_sigbit3)) != 0) {
  331.       if (video_doing_fps)
  332.         video_do_fps (&video_rastport[video_which]);
  333.       if (video_palette_changed > 0) {
  334.         LoadRGB32 (&video_screen->ViewPort, video_colourtable);
  335.         video_palette_changed--; /* keep it set for 2 frames for dblbuffering */
  336.       }
  337.       if ((ChangeScreenBuffer (video_screen, video_sb[video_which])) != 0) {
  338.         video_disp = FALSE;
  339.         video_safe = FALSE;
  340.       }
  341.       if (!video_safe) {  /* wait until safe */
  342.         Wait (1 << video_safeport->mp_SigBit);
  343.         while (GetMsg (video_safeport) != NULL) /* clear message queue */
  344.           /* do nothing */ ;
  345.         video_safe = TRUE;
  346.       }
  347.       Signal (video_maintask, SIGBREAKF_CTRL_F);
  348.       if (!video_disp) {  /* wait for previous frame to be displayed */
  349.         Wait (1 << video_dispport->mp_SigBit);
  350.         while (GetMsg (video_dispport) != NULL) /* clear message queue */
  351.           /* do nothing */ ;
  352.         video_disp = TRUE;
  353.       }
  354.     }
  355.     if ((sig & SIGBREAKF_CTRL_C) != 0) {
  356.       going = FALSE;
  357.     }
  358.   }
  359.   if (!video_safe) {  /* wait for safe */
  360.     Wait (1 << video_safeport->mp_SigBit);
  361.     while (GetMsg (video_safeport) != NULL) /* clear message queue */
  362.       /* do nothing */ ;
  363.     video_safe = TRUE;
  364.   }
  365.   if (!video_disp) {  /* wait for last frame to be displayed */
  366.     Wait (1 << video_dispport->mp_SigBit);
  367.     while (GetMsg (video_dispport) != NULL) /* clear message queue */
  368.       /* do nothing */ ;
  369.     video_disp = TRUE;
  370.   }
  371.   if (video_sigbit3 != -1)
  372.     FreeSignal (video_sigbit3);
  373.   if (video_dispport != NULL)
  374.     DeletePort (video_dispport);
  375.   if (video_safeport != NULL)
  376.     DeletePort (video_safeport);
  377.   Signal (video_maintask, SIGBREAKF_CTRL_F);
  378.   Wait (0);
  379. }
  380.  
  381. /**********************************************************************/
  382. // Called by D_DoomMain,
  383. // determines the hardware configuration
  384. // and sets up the video mode
  385. void I_InitGraphics (void)
  386. {
  387.   int i;
  388.   ULONG propertymask, idcmp, wflags, width, pixfmt;
  389.   struct Rectangle rect;
  390.   char reqtitle[32];
  391.   int mode, depth, nbytes, p;
  392.   DisplayInfoHandle handle;
  393.   struct DisplayInfo dispinfo;
  394.   struct DimensionInfo dimsinfo;
  395.  
  396.   video_maintask = FindTask(NULL);
  397.  
  398.   if (AslBase == NULL) {
  399.     if ((AslBase = OpenLibrary ("asl.library", 37L)) == NULL ||
  400.         (video_smr = AllocAslRequestTags (ASL_ScreenModeRequest, TAG_DONE)) == NULL) {
  401.       I_Error ("OpenLibrary(""asl.library"", 37) failed");
  402.     }
  403.   }
  404.  
  405.   if ((timermp = CreatePort (NULL, 0)) == NULL)
  406.     I_Error ("Can't create messageport!");
  407.   if ((timerio = (struct timerequest *)CreateExtIO (timermp,
  408.                   sizeof(struct timerequest))) == NULL)
  409.     I_Error ("Can't create External IO!");
  410.   if (timerclosed = OpenDevice (TIMERNAME, UNIT_ECLOCK,
  411.                                 (struct IORequest *)timerio, 0))
  412.     I_Error ("Can't open timer.device!");
  413.   TimerBase = (struct Library *)timerio->tr_node.io_Device;
  414.   eclocks_per_second = ReadEClock (&start_time);
  415.  
  416.   video_doing_fps = M_CheckParm ("-fps");
  417.  
  418.   /* first check tooltypes for SCREENMODE */
  419.   mode = -1;
  420.   p = M_CheckParm ("-screenmode");
  421.   if (p && p < myargc - 1) {
  422.     mode = parse_mode (myargv[p+1]);
  423.   }
  424.  
  425.   /* if not found in icon tooltypes, then put up a ScreenMode requester */
  426.   if (mode == -1) {
  427.     propertymask = /* DIPF_IS_EXTRAHALFBRITE | */ DIPF_IS_DUALPF |
  428.                    DIPF_IS_PF2PRI | DIPF_IS_HAM;
  429.     if (GfxBase->LibNode.lib_Version >= 39)
  430.       mode = BestModeID (BIDTAG_NominalWidth,     SCREENWIDTH,
  431.                          BIDTAG_NominalHeight,    SCREENHEIGHT,
  432.                          BIDTAG_Depth,            video_depth,
  433.                          BIDTAG_DIPFMustNotHave,  propertymask,
  434.                          TAG_DONE);
  435.     else
  436.       mode = EXTRAHALFBRITE_KEY;
  437.     if (AslBase->lib_Version >= 38) {
  438.       sprintf (reqtitle, "ADoom %dx%d", SCREENWIDTH, SCREENHEIGHT);
  439.       if (!AslRequestTags (video_smr,
  440.                            ASLSM_TitleText,        (ULONG)reqtitle,
  441.                            ASLSM_InitialDisplayID, mode,
  442.                            ASLSM_MinWidth,         SCREENWIDTH,
  443.                            ASLSM_MinHeight,        SCREENHEIGHT,
  444.                            ASLSM_MinDepth,         6,
  445.                            ASLSM_MaxDepth,         8,
  446.                            ASLSM_PropertyMask,     propertymask,
  447.                            ASLSM_PropertyFlags,    0,
  448.                            TAG_DONE)) {
  449.         I_Error ("AslRequest() failed");
  450.       }
  451.       mode = video_smr->sm_DisplayID;
  452.     }
  453.   }
  454.  
  455.   if ((handle = FindDisplayInfo (mode)) == NULL) {
  456.     I_Error ("Can't FindDisplayInfo() for mode %08x", mode);
  457.   }
  458.   if ((nbytes = GetDisplayInfoData (handle, (UBYTE *)&dispinfo,
  459.                                     sizeof(struct DisplayInfo), DTAG_DISP,
  460.                                     NULL)) < 40 /*sizeof(struct DisplayInfo)*/) {
  461.     I_Error ("Can't GetDisplayInfoData() for mode %08x, got %d bytes",
  462.              mode, nbytes);
  463.   }
  464.   if ((nbytes = GetDisplayInfoData (handle, (UBYTE *)&dimsinfo,
  465.                                     sizeof(dimsinfo), DTAG_DIMS,
  466.                                     NULL)) < 66 /* sizeof(dimsinfo)*/) {
  467.     I_Error ("Can't GetDisplayInfoData() for mode %08x, got %d bytes",
  468.              mode, nbytes);
  469.   }
  470.  
  471.   video_oscan_height = dimsinfo.MaxOScan.MaxY - dimsinfo.MaxOScan.MinY + 1;
  472.  
  473.   video_is_cyber_mode = 0;
  474.   if ((CyberGfxBase = OpenLibrary ("cybergraphics.library", 0)) != NULL) {
  475.     video_is_cyber_mode = IsCyberModeID (mode);
  476.   }
  477.  
  478.   /* this test needs improving */
  479.   video_is_native_mode = ((GfxBase->LibNode.lib_Version < 39 ||
  480.                            (dispinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE) != 0 ||
  481.                            (dispinfo.PropertyFlags & DIPF_IS_AA) != 0 ||
  482.                            (dispinfo.PropertyFlags & DIPF_IS_ECS) != 0 ||
  483.                            (dispinfo.PropertyFlags & DIPF_IS_DBUFFER) != 0) &&
  484.                           !video_is_cyber_mode &&
  485.                           (dispinfo.PropertyFlags & DIPF_IS_FOREIGN) == 0);
  486.  
  487.   video_is_ehb_mode = ((dispinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE) != 0);
  488.  
  489.   /* manual overrides */
  490.   if (M_CheckParm ("-rtg"))
  491.     video_is_native_mode = FALSE;
  492.   else if (M_CheckParm ("-native"))
  493.     video_is_native_mode = TRUE;
  494.   if (M_CheckParm ("-ehb"))
  495.     video_is_ehb_mode = TRUE;
  496.  
  497.   printf ("Screen Mode $%08x is ", mode);
  498.   if (video_is_native_mode)
  499.     printf (" NATIVE-PLANAR");
  500.   else
  501.     printf (" FOREIGN");
  502.   if (video_is_ehb_mode)
  503.     printf (" EXTRAHALFBRITE");
  504.   else
  505.     printf (" 8-BIT");
  506.   if (video_is_cyber_mode)
  507.     printf (" CYBERGRAPHX");
  508.   printf ("\n");
  509.  
  510.   if (video_is_ehb_mode)
  511.     video_depth = 6;
  512.   else
  513.     video_depth = 8;
  514.  
  515.   rect.MinX = 0;
  516.   rect.MinY = 0;
  517.   rect.MaxX = SCREENWIDTH - 1;
  518.   rect.MaxY = SCREENHEIGHT - 1;
  519.  
  520.   if (M_CheckParm ("-mmu") && cpu_type >= 68040)
  521.        video_use_mmu = true;
  522.  
  523.   if (video_is_native_mode) {
  524.     video_is_using_blitter = (cpu_type < 68040);
  525.  
  526.     for (i = 0; i < (video_is_using_blitter ? 2 : 3); i++) {
  527.       /* use the mmu hack only if cpu is 68040+ and user specified -mmu */
  528.       if (video_use_mmu) {
  529.         ULONG *ptr, mem;
  530.         mem = (ULONG)AllocVec (SCREENWIDTH * SCREENHEIGHT / 8 * video_depth +
  531.                                4100, MEMF_CHIP);
  532.         if (!mem)
  533.           I_Error ("AllocVec() failed");
  534.         ptr = (ULONG*)((mem & ~0xfff) + 4096);
  535.     ptr[-1] = 4096 - (mem & 0xfff);
  536.     video_raster[i] = (byte *)ptr;
  537.         video_c_cache_mode = mmu_mark (video_raster[i],
  538.                                    SCREENWIDTH * SCREENHEIGHT / 8 * video_depth,
  539.                                    CM_IMPRECISE, SysBase);
  540.       } else {
  541.         if ((video_raster[i] = (PLANEPTR)AllocRaster (SCREENWIDTH,
  542.                                            video_depth * SCREENHEIGHT)) == NULL)
  543.           I_Error ("AllocRaster() failed");
  544.       }
  545.       memset (video_raster[i], 0, video_depth * RASSIZE (SCREENWIDTH, SCREENHEIGHT));
  546.       InitBitMap (&video_bitmap[i], video_depth, SCREENWIDTH, SCREENHEIGHT);
  547.       for (depth = 0; depth < video_depth; depth++)
  548.         video_bitmap[i].Planes[depth] = video_raster[i] +
  549.                                     depth * RASSIZE (SCREENWIDTH, SCREENHEIGHT);
  550.       InitRastPort (&video_rastport[i]);
  551.       video_rastport[i].BitMap = &video_bitmap[i];
  552.       SetAPen (&video_rastport[i], (1 << video_depth) - 1);
  553.       SetBPen (&video_rastport[i], 0);
  554.       SetDrMd (&video_rastport[i], JAM2);
  555.     }
  556.  
  557.     /* experimental c2p stuff */
  558.     if (!video_is_using_blitter)
  559.       c2p = c2p8_reloc (screens[0], &video_bitmap[0], SysBase);
  560.  
  561.     if ((video_screen = OpenScreenTags (NULL,
  562.           SA_Type,        CUSTOMSCREEN | CUSTOMBITMAP,
  563.           SA_DisplayID,   mode,
  564.           SA_DClip,       (ULONG)&rect,
  565.           SA_Width,       SCREENWIDTH,
  566.           SA_Height,      SCREENHEIGHT,
  567.           SA_Depth,       video_depth,
  568.           /* SA_Draggable,FALSE, */
  569.           /* SA_AutoScroll,FALSE, */
  570.           /* SA_Exclusive,TRUE, */
  571.           SA_Quiet,       TRUE,
  572.           SA_BitMap,      &video_bitmap[0], /* custom bitmap, contiguous planes */
  573.           TAG_DONE)) == NULL) {
  574.       I_Error ("OpenScreen() failed");
  575.     }
  576.     for (i = 0; i < (video_is_using_blitter ? 2 : 3); i++) {
  577.       if ((video_compare_buffer[i] = malloc (SCREENWIDTH * SCREENHEIGHT)) == NULL)
  578.         I_Error ("Out of memory allocating %d bytes", SCREENWIDTH * SCREENHEIGHT);
  579.       memset (video_compare_buffer[i], 0, SCREENWIDTH * SCREENHEIGHT);
  580.     }
  581.     if (video_is_using_blitter) {
  582.       for (i = 0; i < 2; i++) {
  583.     if ((video_sb[i] = AllocScreenBuffer (video_screen, &video_bitmap[i], 0)) == NULL)
  584.       I_Error ("Can't allocate structure for double buffering");
  585.       }
  586.     } else {
  587.       video_db = AllocDBufInfo (&video_screen->ViewPort);
  588.       video_mp = CreateMsgPort ();
  589.       if (!video_db || !video_mp)
  590.         I_Error ("Can't allocate dbuffer information");
  591.       video_db->dbi_DispMessage.mn_ReplyPort = video_mp;
  592.       video_which = 1;
  593.       ChangeVPBitMap (&video_screen->ViewPort, &video_bitmap[0], video_db);
  594.     }
  595.   } else {  /* non-native ScreenMode */
  596.     if (video_is_cyber_mode && M_CheckParm ("-directcgx"))
  597.       video_is_directcgx = TRUE;
  598.     if ((video_screen = OpenScreenTags (NULL,
  599.           SA_Type,        CUSTOMSCREEN,
  600.           SA_DisplayID,   mode,
  601.           SA_DClip,       (ULONG)&rect,
  602.           SA_Width,       SCREENWIDTH,
  603.           SA_Height,      video_is_directcgx ? video_oscan_height << 1 : SCREENHEIGHT,
  604.           SA_Depth,       video_depth,
  605.           /* SA_Draggable,FALSE, */
  606.           /* SA_AutoScroll,FALSE, */
  607.           /* SA_Exclusive,TRUE, */
  608.           SA_Quiet,       TRUE,
  609.           TAG_DONE)) == NULL) {
  610.       I_Error ("OpenScreen() failed");
  611.     }
  612.   }
  613.  
  614.   if (video_is_directcgx) {
  615.     video_bitmap_handle = LockBitMapTags (video_screen->ViewPort.RasInfo->BitMap,
  616.                                           LBMI_WIDTH,       &width,
  617.                                           LBMI_DEPTH,       &depth,
  618.                                           LBMI_PIXFMT,      &pixfmt,
  619.                                           LBMI_BASEADDRESS, &screens[0],
  620.                                           TAG_DONE);
  621.     UnLockBitMap (video_bitmap_handle);
  622.     if (/* width != SCREENWIDTH || */
  623.         depth != video_depth ||
  624.         pixfmt != PIXFMT_LUT8) {
  625.       I_Error ("ScreenMode of width %d, depth %d, pixfmt %d cannot be used with -directcgx",
  626.                width, depth, pixfmt);
  627.     }
  628.   } else {
  629.     if (video_use_mmu) {
  630.       video_f_cache_mode = mmu_mark (screens[0],
  631.                                      (SCREENWIDTH * SCREENHEIGHT + 4096) & ~0xfff,
  632.                                      CM_WRITETHROUGH, SysBase);
  633.     }
  634.   }
  635.  
  636.   idcmp = IDCMP_RAWKEY;
  637.   wflags = WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_RMBTRAP;
  638.   if (M_CheckParm("-mouse") != NULL) {
  639.     idcmp |= IDCMP_MOUSEMOVE | IDCMP_DELTAMOVE | IDCMP_MOUSEBUTTONS;
  640.     wflags |= WFLG_REPORTMOUSE;
  641.   }
  642.  
  643.   if ((video_window = OpenWindowTags (NULL,
  644.         WA_Left,         0,
  645.         WA_Top,          0,
  646.         WA_Width,        SCREENWIDTH,
  647.         WA_Height,       SCREENHEIGHT,
  648.         WA_IDCMP,        idcmp,
  649.         WA_Flags,        wflags,
  650.         WA_CustomScreen, video_screen,
  651.         TAG_DONE)) == NULL) {
  652.     I_Error ("OpenWindow() failed");
  653.   }
  654.  
  655.   InitBitMap (&video_tmp_bm, video_depth, SCREENWIDTH, 1);
  656.   for (depth = 0; depth < video_depth; depth++)
  657.     if ((video_tmp_bm.Planes[depth] = (PLANEPTR)AllocRaster (SCREENWIDTH, 1)) == NULL)
  658.       I_Error ("AllocRaster() failed");
  659.   video_temprp = *video_window->RPort;
  660.   video_temprp.Layer = NULL;
  661.   video_temprp.BitMap = &video_tmp_bm;
  662.  
  663.   if (!M_CheckParm ("-mousepointer"))
  664.     SetPointer (video_window, emptypointer, 1, 16, 0, 0);
  665.  
  666.   if (video_is_native_mode) {
  667.     if (video_is_using_blitter) {
  668.       if ((video_sigbit1 = AllocSignal(-1)) == -1 ||
  669.       (video_sigbit2 = AllocSignal(-1)) == -1)
  670.     I_Error ("Can't allocate signal!\n");
  671.       Signal (video_maintask, (1 << video_sigbit1) | (1 << video_sigbit2));
  672.                                                 /* initial state is finished */
  673.       if ((video_fliptask = CreateTask ("ADoom_flipscreen", 100,
  674.                     video_flipscreentask, 4096)) == NULL)
  675.     I_Error ("Can't create subtask");
  676.       Wait (SIGBREAKF_CTRL_F);
  677.       if (video_sigbit3 == -1)
  678.     I_Error ("Subtask couldn't allocate sigbit");
  679.       if (!video_is_ehb_mode)
  680.         c2p1x1_cpu3blit1_queue_init (SCREENWIDTH, SCREENHEIGHT, 0,
  681.                                      SCREENWIDTH * SCREENHEIGHT / 8,
  682.                                      1 << video_sigbit1, 1 << video_sigbit3,
  683.                                      video_maintask, video_fliptask);
  684.     }
  685.   }
  686.  
  687.   /* joystick initialisation */
  688.  
  689.   if (M_CheckParm ("-sega3") != NULL)
  690.     sega3_selected = TRUE;
  691.  
  692.   if (M_CheckParm ("-sega6") != NULL)
  693.     sega6_selected = TRUE;
  694.  
  695.   if (M_CheckParm ("-joypad") != NULL) {
  696.  
  697.     if ((LowLevelBase = OpenLibrary ("lowlevel.library", 0)) == NULL)
  698.       I_Error ("-joypad option specified and can't open lowlevel.library");
  699.  
  700.   } else {
  701.  
  702.     if ((gameport_mp = CreatePort (NULL, 0)) == NULL ||
  703.         (gameport_io = (struct IOStdReq *)CreateExtIO (gameport_mp,
  704.                                               sizeof(struct IOStdReq))) == NULL ||
  705.         OpenDevice ("gameport.device", 1, (struct IORequest *)gameport_io, 0) != 0)
  706.       I_Error ("Can't open gameport.device");
  707.  
  708.     gameport_is_open = TRUE;
  709.  
  710.     Forbid ();
  711.  
  712.     gameport_io->io_Command = GPD_ASKCTYPE;
  713.     gameport_io->io_Length = 1;
  714.     gameport_io->io_Data = &gameport_ct;
  715.     DoIO ((struct IORequest *)gameport_io);
  716.  
  717.     if (gameport_ct != GPCT_NOCONTROLLER) {
  718.  
  719.       Permit ();
  720.       fprintf (stderr, "Another task is using the gameport!  Joystick disabled");
  721.       CloseDevice ((struct IORequest *)gameport_io);
  722.       gameport_is_open = FALSE;
  723.  
  724.     } else {
  725.  
  726.       gameport_ct = GPCT_ABSJOYSTICK;
  727.       gameport_io->io_Command = GPD_SETCTYPE;
  728.       gameport_io->io_Length = 1;
  729.       gameport_io->io_Data = &gameport_ct;
  730.       DoIO ((struct IORequest *)gameport_io);
  731.  
  732.       Permit ();
  733.  
  734.       gameport_io->io_Command = GPD_SETTRIGGER;
  735.       gameport_io->io_Length = sizeof(struct GamePortTrigger);
  736.       gameport_io->io_Data = &gameport_gpt;
  737.       DoIO ((struct IORequest *)gameport_io);
  738.  
  739.       gameport_io->io_Command = GPD_READEVENT;
  740.       gameport_io->io_Length = sizeof (struct InputEvent);
  741.       gameport_io->io_Data = &gameport_ie;
  742.       SendIO ((struct IORequest *)gameport_io);
  743.       gameport_io_in_progress = TRUE;
  744.     }
  745.   }
  746. }
  747.  
  748. /**********************************************************************/
  749. void I_ShutdownGraphics (void)
  750. {
  751.   int depth, i;
  752.  
  753.   if (video_is_directcgx && video_bitmap_is_locked) {
  754.     UnLockBitMap (video_bitmap_handle);
  755.     video_bitmap_is_locked = FALSE;
  756.   }
  757.   if (LowLevelBase != NULL) {
  758.     CloseLibrary (LowLevelBase);
  759.     LowLevelBase = NULL;
  760.   }
  761.   if (gameport_io_in_progress) {
  762.     AbortIO ((struct IORequest *)gameport_io);
  763.     WaitIO ((struct IORequest *)gameport_io);
  764.     gameport_io_in_progress = FALSE;
  765.     gameport_ct = GPCT_NOCONTROLLER;
  766.     gameport_io->io_Command = GPD_SETCTYPE;
  767.     gameport_io->io_Length = 1;
  768.     gameport_io->io_Data = &gameport_ct;
  769.     DoIO ((struct IORequest *)gameport_io);
  770.   }
  771.   if (gameport_is_open) {
  772.     CloseDevice ((struct IORequest *)gameport_io);
  773.     gameport_is_open = FALSE;
  774.   }
  775.   if (gameport_io != NULL) {
  776.     DeleteExtIO ((struct IORequest *)gameport_io);
  777.     gameport_io = NULL;
  778.   }
  779.   if (gameport_mp != NULL) {
  780.     DeletePort (gameport_mp);
  781.     gameport_mp = NULL;
  782.   }
  783.   if (video_blit_is_in_progress) {
  784.     Wait (SIGBREAKF_CTRL_F);
  785.     video_blit_is_in_progress = FALSE;
  786.   }
  787.   if (video_fliptask != NULL) {
  788.     Signal (video_fliptask, SIGBREAKF_CTRL_C);
  789.     Wait (SIGBREAKF_CTRL_F);
  790.     DeleteTask (video_fliptask);
  791.     video_fliptask = NULL;
  792.   }
  793.   if (video_is_using_blitter) {
  794.     if (video_sigbit1 != -1) {
  795.       Wait (1 << video_sigbit1);  // wait for last c2p8 to finish pass 3
  796.     FreeSignal (video_sigbit1);
  797.       video_sigbit1 = -1;
  798.     }
  799.     if (video_sigbit2 != -1) {
  800.       Wait (1 << video_sigbit2);  // wait for last c2p8 to completely finish
  801.     FreeSignal (video_sigbit2);
  802.       video_sigbit2 = -1;
  803.     }
  804.   }
  805.   if (video_window != NULL) {
  806.     ClearPointer (video_window);
  807.     CloseWindow (video_window);
  808.     video_window = NULL;
  809.   }
  810.   if (video_is_using_blitter) {
  811.     for (i = 0; i < 2; i++) {
  812.       if (video_sb[i] != NULL) {
  813.     FreeScreenBuffer (video_screen, video_sb[i]);
  814.     video_sb[i] = NULL;
  815.       }
  816.     }
  817.   } else {
  818.     if (video_mp) {
  819.       WaitPort (video_mp);
  820.       while (GetMsg(video_mp));
  821.       DeleteMsgPort (video_mp);
  822.       video_mp = NULL; 
  823.     }
  824.     if (video_db) {
  825.       FreeDBufInfo (video_db);
  826.       video_db = NULL;
  827.     }
  828.   }
  829.   if (video_screen != NULL) {
  830.     CloseScreen (video_screen);
  831.     video_screen = NULL;
  832.   }
  833.   for (depth = 0; depth < video_depth; depth++) {
  834.     if (video_tmp_bm.Planes[depth] != NULL) {
  835.       FreeRaster (video_tmp_bm.Planes[depth], SCREENWIDTH, 1);
  836.       video_tmp_bm.Planes[depth] = NULL;
  837.     }
  838.   }
  839.   for (i = 0; i < (video_is_using_blitter ? 2 : 3); i++) {
  840.     if (video_raster[i] != NULL) {
  841.       if (video_use_mmu) {
  842.         ULONG *ptr = (ULONG *)video_raster[i];
  843.         UBYTE *p2 = (UBYTE *)ptr;
  844.         mmu_mark (video_raster[i], SCREENWIDTH * SCREENHEIGHT / 8 * video_depth,
  845.                   video_c_cache_mode, SysBase);
  846.         FreeVec (p2 - ptr[-1]);
  847.       } else
  848.         FreeRaster (video_raster[i], SCREENWIDTH, video_depth * SCREENHEIGHT);
  849.       video_raster[i] = NULL;
  850.     }
  851.     if (video_compare_buffer[i] != NULL) {
  852.       free (video_compare_buffer[i]);
  853.       video_compare_buffer[i] = NULL;
  854.     }
  855.   }
  856.   if (video_use_mmu && !video_is_directcgx) {
  857.     if (screens[0] != NULL)
  858.       mmu_mark (screens[0], (SCREENWIDTH * SCREENHEIGHT + 4096) & ~0xfff,
  859.                 video_f_cache_mode, SysBase);
  860.   }
  861.   if (CyberGfxBase == NULL) {
  862.     CloseLibrary (CyberGfxBase);
  863.     CyberGfxBase = NULL;
  864.   }
  865.   /* experimental c2p stuff */
  866.   if (c2p && !video_is_using_blitter) {
  867.     c2p8_deinit (c2p, SysBase);
  868.     c2p = NULL;
  869.   }
  870.   if (!timerclosed) {
  871.     if (!CheckIO((struct IORequest *)timerio)) {
  872.       AbortIO ((struct IORequest *)timerio);
  873.       WaitIO ((struct IORequest *)timerio);
  874.     }
  875.     CloseDevice ((struct IORequest *)timerio);
  876.     timerclosed = TRUE;
  877.     TimerBase = NULL;
  878.   }
  879.   if (timerio != NULL) {
  880.     DeleteExtIO ((struct IORequest *)timerio);
  881.     timerio = NULL;
  882.   }
  883.   if (timermp != NULL) {
  884.     DeletePort (timermp);
  885.     timermp = NULL;
  886.   }
  887. }
  888.  
  889. /**********************************************************************/
  890. // Takes full 8 bit values.
  891. void I_SetPalette (byte *palette)
  892. {
  893.   int i;
  894.   static UBYTE gpalette[3*256];
  895.  
  896.   /* printf ("I_SetPalette()\n"); */
  897.   if (video_is_ehb_mode) {
  898.     i = 3 * 256 - 1;
  899.     do {
  900.       gpalette[i] = gammatable[usegamma][palette[i]];
  901.     } while (--i);
  902.     video_colourtable[0] = (32 << 16) + 0;
  903.     median_cut (gpalette, &video_colourtable[1], video_xlate);
  904.     video_colourtable[33] = 0;
  905.   } else {
  906.     i = 3 * 256 - 1;
  907.     video_colourtable[i + 2] = 0;
  908.     do {
  909.       // Better to define c locally here instead of for the whole function:
  910.       ULONG c = gammatable[usegamma][palette[i]];
  911.       c += (c << 8);
  912.       c += (c << 16);
  913.       video_colourtable[i + 1] = c;
  914.     } while (--i);
  915.     video_colourtable[0] = (256 << 16) + 0;
  916.   }
  917.   if (video_is_ehb_mode)
  918.     if (video_is_using_blitter) {
  919.       video_palette_changed = 2;  /* double buffering */
  920.     } else
  921.       video_palette_changed = 3;  /* triple buffering */
  922.   else
  923.     video_palette_changed = 1;
  924. }
  925.  
  926. /**********************************************************************/
  927. void I_StartUpdate (void)
  928. {
  929.   UBYTE *base_address;
  930.  
  931.   if (video_is_directcgx) {
  932.     if (video_palette_changed != 0) {
  933.       LoadRGB32 (&video_screen->ViewPort, video_colourtable);
  934.       video_palette_changed = 0;
  935.     }
  936.     if (!video_bitmap_is_locked) {
  937.       start_timer ();
  938.       video_bitmap_handle = LockBitMapTags (video_screen->ViewPort.RasInfo->BitMap,
  939.                                             LBMI_BASEADDRESS, &base_address,
  940.                                             TAG_DONE);
  941.       lock_time += end_timer ();
  942.       video_bitmap_is_locked = TRUE;
  943. /*
  944.       video_which = 1 - video_which;
  945.       if (video_which != 0)
  946.         screens[0] = base_address + (SCREENWIDTH * video_oscan_height);
  947.       else
  948. */
  949.       screens[0] = base_address;
  950.     }
  951.   }
  952. }
  953.  
  954. /**********************************************************************/
  955. void I_UpdateNoBlit (void)
  956. {
  957. }
  958.  
  959. /**********************************************************************/
  960. void I_FinishUpdate (void)
  961. /* This needs optimising to copy just the parts that changed,
  962.    especially if the user has shrunk the playscreen. */
  963. {
  964.   int top, left, width, height;
  965.  
  966.   total_frames++;
  967.  
  968.   if (video_is_directcgx) {
  969.     if (video_bitmap_is_locked) {
  970.       UnLockBitMap (video_bitmap_handle);
  971.       video_bitmap_is_locked = FALSE;
  972. /*
  973.       video_screen->ViewPort.RasInfo->RyOffset = video_which != 0 ?
  974.                                                          video_oscan_height : 0;
  975.       ScrollVPort (&video_screen->ViewPort);
  976. */
  977.     } else
  978.       I_Error ("I_FinishUpdate() called without calling I_StartUpdate() first");
  979.  
  980.     if (video_doing_fps)
  981.       video_do_fps (video_window->RPort);
  982.     return;
  983.   }
  984.  
  985.   /* experiment to update only the viewwindow except when required */
  986. /*
  987.   if ((video_is_ehb_mode &&
  988.        (video_palette_changed || (total_frames & 2) == 0)) ||
  989.       (!video_is_ehb_mode && (total_frames & 3) == 1)) {
  990. */
  991.     left = 0;
  992.     top = 0;
  993.     width = SCREENWIDTH;
  994.     height = SCREENHEIGHT;
  995. /*
  996.   } else {
  997.     left = viewwindowx;
  998.     top = viewwindowy;
  999.     width = scaledviewwidth;
  1000.     height = viewheight;
  1001.   }
  1002. */
  1003.  
  1004.   if (video_is_native_mode) {
  1005.     if (video_is_using_blitter) {
  1006.       start_timer();
  1007.       Wait (1 << video_sigbit1); /* wait for prev c2p() to finish pass 3 */
  1008.       blit_time += end_timer();
  1009.       if (video_blit_is_in_progress) {
  1010.     start_timer();
  1011.     Wait (SIGBREAKF_CTRL_F); /* wait for prev ChangeScreenBuffer() safe */
  1012.     safe_time += end_timer();
  1013.     video_blit_is_in_progress = FALSE;
  1014.       }
  1015.       video_which = 1 - video_which;  /* render to the hidden bitmap */
  1016.       start_timer();
  1017.       if (video_is_ehb_mode) {
  1018.         c2p_6_020 (&screens[0][SCREENWIDTH * top],
  1019.                    video_bitmap[video_which].Planes,
  1020.                    1 << video_sigbit1, 1 << video_sigbit2, 1 << video_sigbit3,
  1021.                    SCREENWIDTH * height, (SCREENWIDTH >> 3) * top,
  1022.                    video_xlate, video_fliptask);
  1023.       } else {
  1024.         if (cpu_type < 68030)
  1025.           c2p_8_020 (&screens[0][SCREENWIDTH * top],
  1026.                      video_bitmap[video_which].Planes,
  1027.                      1 << video_sigbit1, 1 << video_sigbit2, 1 << video_sigbit3,
  1028.                      SCREENWIDTH * height, (SCREENWIDTH >> 3) * top,
  1029.                      video_fliptask);
  1030.         else
  1031.           c2p1x1_cpu3blit1_queue (screens[0], video_raster[video_which]);
  1032.       }
  1033.       c2p_time += end_timer();
  1034.       video_blit_is_in_progress = TRUE;
  1035.     } else {
  1036.       start_timer();
  1037.       if (video_is_ehb_mode) {
  1038.         c2p_6_040 (screens[0], video_raster[video_which],
  1039.                    video_compare_buffer[video_which], video_xlate,
  1040.                    (SCREENWIDTH * SCREENHEIGHT) >> 3,
  1041.                    video_palette_changed);
  1042.         if (video_palette_changed > 0) {
  1043.           if (video_palette_changed == 3)
  1044.             LoadRGB32 (&video_screen->ViewPort, video_colourtable);
  1045.           video_palette_changed--;
  1046.         }
  1047.       } else {
  1048.         if (c2p && scaledviewwidth >= SCREENWIDTH-64)
  1049.            c2p (screens[0], video_raster[video_which],
  1050.                 screens[0] + SCREENWIDTH * SCREENHEIGHT);
  1051.         else
  1052.           c2p_8_040 (screens[0], video_raster[video_which],
  1053.                      video_compare_buffer[video_which],
  1054.                    (SCREENWIDTH * SCREENHEIGHT) >> 3);
  1055.         if (video_palette_changed != 0) {
  1056.           LoadRGB32 (&video_screen->ViewPort, video_colourtable);
  1057.           video_palette_changed = 0;
  1058.         }
  1059.       }
  1060.       c2p_time += end_timer();
  1061.       if (video_doing_fps)
  1062.         video_do_fps (&video_rastport[video_which]);
  1063.       WaitPort (video_mp);
  1064.       while (GetMsg (video_mp))
  1065.     /* do nothing */ ;
  1066.       ChangeVPBitMap (&video_screen->ViewPort, &video_bitmap[video_which],
  1067.                       video_db);
  1068.       if (++video_which == 3)
  1069.         video_which = 0;
  1070.     }
  1071.   } else {  /* non-native ScreenMode */
  1072.     if (video_palette_changed != 0) {
  1073.       LoadRGB32 (&video_screen->ViewPort, video_colourtable);
  1074.       video_palette_changed = 0;
  1075.     }
  1076.     start_timer();
  1077.     WritePixelArray8 (video_window->RPort, 0, top, SCREENWIDTH-1,
  1078.                       top+height-1, &screens[0][SCREENWIDTH * top],
  1079.                       &video_temprp);
  1080.     wpa8_time += end_timer();
  1081.     if (video_doing_fps)
  1082.       video_do_fps (video_window->RPort);
  1083.   }
  1084. }
  1085.  
  1086. /**********************************************************************/
  1087. // Wait for vertical retrace or pause a bit.  Use when quit game.
  1088. void I_WaitVBL(int count)
  1089. {
  1090.   for ( ; count > 0; count--)
  1091.     WaitTOF();
  1092. }
  1093.  
  1094. /**********************************************************************/
  1095. void I_ReadScreen (byte* scr)
  1096. {
  1097. /*
  1098.   if (video_is_directcgx) {
  1099.     printf ("I_ReadScreen() %d %d\n", video_which, video_bitmap_is_locked);
  1100.     ReadPixelArray8 (&video_rastport[0], 0,
  1101.                      video_which != 0 ? 0 : video_oscan_height,
  1102.                      SCREENWIDTH-1, SCREENHEIGHT-1, scr, &video_temprp);
  1103.   } else
  1104. */
  1105. /*
  1106.   if (video_is_directcgx)
  1107.     if (video_which)
  1108.       memcpy (scr, screens[0] - SCREENWIDTH * video_oscan_height,
  1109.               SCREENWIDTH * SCREENHEIGHT);
  1110.     else
  1111.       memcpy (scr, screens[0] + SCREENWIDTH * video_oscan_height,
  1112.               SCREENWIDTH * SCREENHEIGHT);
  1113.   else
  1114. */
  1115.   memcpy (scr, screens[0], SCREENWIDTH * SCREENHEIGHT);
  1116. }
  1117.  
  1118. /**********************************************************************/
  1119. void I_BeginRead (void)
  1120. {
  1121. }
  1122.  
  1123. /**********************************************************************/
  1124. void I_EndRead (void)
  1125. {
  1126. }
  1127.  
  1128. /**********************************************************************/
  1129.  
  1130. ULONG Sega3(void);
  1131. ULONG Sega6(void);
  1132.  
  1133.  
  1134. void amiga_getevents (void)
  1135. {
  1136.   event_t event;
  1137.   ULONG class;
  1138.   UWORD code;
  1139.   WORD mousex, mousey;
  1140.   struct IntuiMessage *msg;
  1141.   static ULONG previous = 0;
  1142.   static int xlate[0x68] = {
  1143.     '`', '1', '2', '3', '4', '5', '6', '7',
  1144.     '8', '9', '0', KEY_MINUS, KEY_EQUALS, '\\', 0, '0',
  1145.     'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
  1146.     'o', 'p', KEY_F11, KEY_F12, 0, '0', '2', '3',
  1147.     'a', 's', 'd', 'f', 'g', 'h', 'j', 'k',
  1148.     'l', ';', '\'', KEY_ENTER, 0, '4', '5', '6',
  1149.     KEY_RSHIFT, 'z', 'x', 'c', 'v', 'b', 'n', 'm',
  1150.     ',', '.', '/', 0, '.', '7', '8', '9',
  1151.     ' ', KEY_BACKSPACE, KEY_TAB, KEY_ENTER, KEY_ENTER, KEY_ESCAPE, KEY_BACKSPACE,
  1152.     0, 0, 0, KEY_MINUS, 0, KEY_UPARROW, KEY_DOWNARROW, KEY_RIGHTARROW, KEY_LEFTARROW,
  1153.     KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8,
  1154.     KEY_F9, KEY_F10, '(', ')', '/', '*', KEY_EQUALS, KEY_PAUSE,
  1155.     KEY_RSHIFT, KEY_RSHIFT, 0, KEY_RCTRL, KEY_LALT, KEY_RALT, 0, KEY_RCTRL
  1156.   };
  1157.   static event_t joyevent = {0}, mouseevent = {0};
  1158.   ULONG currSega;
  1159.  
  1160.   if (video_window != NULL) {
  1161.     while ((msg = (struct IntuiMessage *)GetMsg (video_window->UserPort)) != NULL) {
  1162.       class = msg->Class;
  1163.       code = msg->Code;
  1164.       mousex = msg->MouseX;
  1165.       mousey = msg->MouseY;
  1166.       ReplyMsg ((struct Message *)msg);
  1167.       if (class == IDCMP_RAWKEY) {
  1168.         if ((code & 0x80) != 0) {
  1169.           code &= ~0x80;
  1170.       event.type = ev_keyup;
  1171.         } else {
  1172.           event.type = ev_keydown;
  1173.         }
  1174.         if (code < 0x68 && xlate[code] != 0) {
  1175.           event.data1 = xlate[code];
  1176.           D_PostEvent (&event);
  1177.         }
  1178.       } else if (class == IDCMP_MOUSEMOVE) {
  1179.         mouseevent.type = ev_mouse;
  1180.         mouseevent.data2 = (mousex << 3);
  1181.         mouseevent.data3 = -(mousey << 5);
  1182.         D_PostEvent (&mouseevent);
  1183.       } else if (class == IDCMP_MOUSEBUTTONS) {
  1184.         mouseevent.type = ev_mouse;
  1185.         switch (code) {
  1186.           case SELECTDOWN:
  1187.             mouseevent.data1 |= 1;
  1188.             break;
  1189.           case SELECTUP:
  1190.             mouseevent.data1 &= ~1;
  1191.             break;
  1192.           case MENUDOWN:
  1193.             mouseevent.data1 |= 2;
  1194.             break;
  1195.           case MENUUP:
  1196.             mouseevent.data1 &= ~2;
  1197.             break;
  1198.           case MIDDLEDOWN:
  1199.             mouseevent.data1 |= 4;
  1200.             break;
  1201.           case MIDDLEUP:
  1202.             mouseevent.data1 &= ~4;
  1203.             break;
  1204.           default:
  1205.             break;
  1206.         }
  1207.         D_PostEvent (&mouseevent);
  1208.       }
  1209.     }
  1210.   }
  1211.  
  1212.   if (gameport_is_open && gameport_io_in_progress) {
  1213.     while (GetMsg (gameport_mp) != NULL) {
  1214.       switch (gameport_ie.ie_Code) {
  1215.         case IECODE_LBUTTON:
  1216.           joyevent.data1 |= 1;
  1217.           break;
  1218.         case IECODE_LBUTTON | IECODE_UP_PREFIX:
  1219.           joyevent.data1 &= ~1;
  1220.           break;
  1221.         case IECODE_RBUTTON:
  1222.           joyevent.data1 |= 2;
  1223.           break;
  1224.         case IECODE_RBUTTON | IECODE_UP_PREFIX:
  1225.           joyevent.data1 &= ~2;
  1226.           break;
  1227.         case IECODE_MBUTTON:
  1228.           joyevent.data1 |= 4;
  1229.           break;
  1230.         case IECODE_MBUTTON | IECODE_UP_PREFIX:
  1231.           joyevent.data1 &= ~4;
  1232.           break;
  1233.         case IECODE_NOBUTTON:
  1234.           joyevent.data2 = gameport_ie.ie_X;
  1235.           joyevent.data3 = gameport_ie.ie_Y;
  1236.           break;
  1237.         default:
  1238.           break;
  1239.       }
  1240.       joyevent.type = ev_joystick;
  1241.       D_PostEvent (&joyevent);
  1242.       gameport_io->io_Command = GPD_READEVENT;
  1243.       gameport_io->io_Length = sizeof (struct InputEvent);
  1244.       gameport_io->io_Data = &gameport_ie;
  1245.       SendIO ((struct IORequest *)gameport_io);
  1246.     }
  1247.   }
  1248.  
  1249.   /* CD32 joypad handler code supplied by Gabry (ggreco@iol.it) */
  1250.  
  1251.   if (LowLevelBase != NULL) {
  1252.     event_t joyevent;
  1253.     ULONG joypos = ReadJoyPort (1);
  1254.  
  1255.     if (previous == joypos)
  1256.       return;
  1257.  
  1258.     joyevent.type = ev_joystick;
  1259.     joyevent.data1 = joyevent.data2 = joyevent.data3 = 0;
  1260.  
  1261.     if (joypos & JPF_BUTTON_RED)
  1262.       joyevent.data1 |= 1;
  1263.     else
  1264.       joyevent.data1 &= ~1;
  1265.  
  1266.     if (joypos & JP_DIRECTION_MASK) {
  1267.       if (joypos & JPF_JOY_LEFT) {
  1268.         joyevent.data2 = -1;
  1269.       } else if (joypos & JPF_JOY_RIGHT) {
  1270.         joyevent.data2 = 1;
  1271.       }
  1272.       if (joypos & JPF_JOY_UP) {
  1273.         joyevent.data3 = -1;
  1274.       } else if (joypos & JPF_JOY_DOWN) {
  1275.         joyevent.data3 = 1;
  1276.       }
  1277.     }
  1278.  
  1279.     if (joypos & JP_TYPE_GAMECTLR) {
  1280.       event_t event;
  1281.  
  1282.       // Play/Pause = ESC (Menu)
  1283.       if (joypos & JPF_BUTTON_PLAY && !(previous & JPF_BUTTON_PLAY)) {
  1284.         event.type = ev_keydown;
  1285.         event.data1 = KEY_ESCAPE;
  1286.         D_PostEvent (&event);
  1287.       } else if (previous & JPF_BUTTON_PLAY) {
  1288.         event.type = ev_keyup;
  1289.         event.data1 = KEY_ESCAPE;
  1290.         D_PostEvent (&event);
  1291.       }
  1292.  
  1293.       // YELLOW = SHIFT (button 2) (Run)
  1294.       if (joypos & JPF_BUTTON_YELLOW)
  1295.         joyevent.data1 |= 4;
  1296.       else
  1297.         joyevent.data1 &= ~4;
  1298.  
  1299.       // BLUE = SPACE (button 3) (Open/Operate)
  1300.  
  1301.       if (joypos & JPF_BUTTON_BLUE)
  1302.         joyevent.data1 |= 8;
  1303.       else
  1304.         joyevent.data1 &= ~8;
  1305.  
  1306.       // GREEN = RETURN (show msg)
  1307.  
  1308.       if (joypos & JPF_BUTTON_GREEN && !(previous&JPF_BUTTON_GREEN)) {
  1309.         event.type = ev_keydown;
  1310.         event.data1 = 13;
  1311.         D_PostEvent (&event);
  1312.       } else if (previous & JPF_BUTTON_GREEN) {
  1313.         event.type = ev_keyup;
  1314.         event.data1 = 13;
  1315.         D_PostEvent (&event);
  1316.       }
  1317.  
  1318.       // FORWARD & REVERSE - ALT (Button1) Strafe left/right
  1319.  
  1320.       if (joypos & JPF_BUTTON_FORWARD) {
  1321.         joyevent.data1 |= 2;
  1322.         joyevent.data2 = 1;
  1323.       } else if (joypos & JPF_BUTTON_REVERSE) {
  1324.         joyevent.data1 |=2;
  1325.         joyevent.data2=-1;
  1326.       } else
  1327.         joyevent.data1 &= ~2;
  1328.     }
  1329.  
  1330.     D_PostEvent (&joyevent);
  1331.  
  1332.     previous = joypos;
  1333.   }
  1334.  
  1335.   /* SEGA joypad handler code by Joe Fenton, loosely based on CD32 handling */
  1336.  
  1337.   if (sega3_selected || sega6_selected) {
  1338.     event_t joyevent, event;
  1339.  
  1340.     if (sega3_selected) {
  1341.       currSega = Sega3 ();
  1342.     } else {
  1343.       currSega = Sega6 ();
  1344.     }
  1345.  
  1346.     if (prevSega == currSega)
  1347.       return;
  1348.  
  1349.     joyevent.type = ev_joystick;
  1350.     joyevent.data1 = joyevent.data2 = joyevent.data3 = 0;
  1351.  
  1352.     // B = fire
  1353.     if (currSega & 0x10)
  1354.       joyevent.data1 |= 1;
  1355.     else
  1356.       joyevent.data1 &= ~1;
  1357.  
  1358.     // directionals
  1359.     if (currSega & 0xF) {
  1360.       if (currSega & 4) {
  1361.         joyevent.data2 = -1;
  1362.       } else if (currSega & 8) {
  1363.         joyevent.data2 = 1;
  1364.       }
  1365.       if (currSega & 1) {
  1366.         joyevent.data3 = -1;
  1367.       } else if (currSega & 2) {
  1368.         joyevent.data3 = 1;
  1369.       }
  1370.     }
  1371.  
  1372.     // Mode = ESC (Menu)
  1373.     if (currSega & 0x80000 && !(prevSega & 0x80000)) {
  1374.       event.type = ev_keydown;
  1375.       event.data1 = KEY_ESCAPE;
  1376.       D_PostEvent (&event);
  1377.     } else if (prevSega & 0x80000) {
  1378.       event.type = ev_keyup;
  1379.       event.data1 = KEY_ESCAPE;
  1380.       D_PostEvent (&event);
  1381.     }
  1382.  
  1383.     // Y = SHIFT (Run)
  1384.     if (currSega & 0x20000)
  1385.       joyevent.data1 |= 4;
  1386.     else
  1387.       joyevent.data1 &= ~4;
  1388.  
  1389.     // Start = SPACE (Open/Operate)
  1390.     if (currSega & 0x2000)
  1391.       joyevent.data1 |= 8;
  1392.     else
  1393.       joyevent.data1 &= ~8;
  1394.  
  1395.     // A & C - ALT (Button1) Strafe left/right
  1396.     if (currSega & 0x20) {
  1397.       joyevent.data1 |= 2;
  1398.       joyevent.data2 = 1;
  1399.     } else if (currSega & 0x1000) {
  1400.       joyevent.data1 |=2;
  1401.       joyevent.data2=-1;
  1402.     } else
  1403.       joyevent.data1 &= ~2;
  1404.  
  1405.     // X = RETURN (show msg)
  1406.     if (currSega & 0x40000 && !(prevSega&0x40000)) {
  1407.       event.type = ev_keydown;
  1408.       event.data1 = 13;
  1409.       D_PostEvent (&event);
  1410.     } else if (prevSega & 0x40000) {
  1411.       event.type = ev_keyup;
  1412.       event.data1 = 13;
  1413.       D_PostEvent (&event);
  1414.     }
  1415.  
  1416.     // Z = TAB (show map)
  1417.     if (currSega & 0x10000 && !(prevSega&0x10000)) {
  1418.       event.type = ev_keydown;
  1419.       event.data1 = 9;
  1420.       D_PostEvent (&event);
  1421.     } else if (prevSega & 0x10000) {
  1422.       event.type = ev_keyup;
  1423.       event.data1 = 9;
  1424.       D_PostEvent (&event);
  1425.     }
  1426.  
  1427.     D_PostEvent (&joyevent);
  1428.  
  1429.     prevSega = currSega;
  1430.   }
  1431.  
  1432. }
  1433.  
  1434. /**********************************************************************/
  1435. static void calc_time (ULONG time, char *msg)
  1436. {
  1437.   printf ("Total %s = %u us  (%u us/frame)\n", msg,
  1438.           (ULONG)(1000000.0 * ((double)time) / ((double)eclocks_per_second)),
  1439.           (ULONG)(1000000.0 * ((double)time) / ((double)eclocks_per_second) /
  1440.                   ((double)total_frames)));
  1441. }
  1442.  
  1443. /**********************************************************************/
  1444. void _STDvideo_cleanup (void)
  1445. {
  1446.   I_ShutdownGraphics ();
  1447.   if (video_smr != NULL) {
  1448.     FreeAslRequest (video_smr);
  1449.     video_smr = NULL;
  1450.   }
  1451.   /* printf ("EClocks per second = %d\n", eclocks_per_second); */
  1452.   if (total_frames > 0) {
  1453.     printf ("Total number of frames = %u\n", total_frames);
  1454.     calc_time (blit_time, "blit wait time ");
  1455.     calc_time (safe_time, "safe wait time ");
  1456.     calc_time (c2p_time,  "C2P time       ");
  1457.     calc_time (wpa8_time, "WPA8 time      ");
  1458.     calc_time (lock_time, "LockBitMap time");
  1459.   }
  1460. }
  1461.  
  1462. /**********************************************************************/
  1463.